﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using TabbedTemplate.Models;

namespace TabbedTemplate.Services
{
    /// <summary>
    /// 同步服务。
    /// </summary>
    public class SyncService : ISyncService
    {
        /******** 公开变量 ********/

        /******** 私有变量 ********/

        /// <summary>
        /// 收藏存储。
        /// </summary>
        private IFavoriteStorage _localFavoriteStorage;

        private IStoreStorage _storeStorage;
        private IPunchInfoStorage _localPunchInfoStorage;
        private IImageService _localImageService;
        /// <summary>
        /// 远程收藏存储。
        /// </summary>
        private IRemoteFavoriteStorage _remoteFavoriteStorage;

        private IRemotePunchInfoStorage _remotePunchInfoStorage;
        /******** 继承方法 ********/

        /// <summary>
        /// 状态。
        /// </summary>
        public string Status
        {
            get => _status;
            set
            {
                _status = value;
                StatusChanged?.Invoke(this, EventArgs.Empty);
            }
        }

        private string _status;

        /// <summary>
        /// 状态改变事件。
        /// </summary>
        public event EventHandler StatusChanged;

        /// <summary>
        /// 远程收藏存储。
        /// </summary>
        public IRemoteFavoriteStorage RemoteFavoriteStorage =>
            _remoteFavoriteStorage;

        public IRemotePunchInfoStorage RemotePunchInfoStorage => _remotePunchInfoStorage;



        /// <summary>
        /// 同步。
        /// </summary>
        public async Task<ServiceResult> SyncAsync()
        {
            Status = "正在读取本地收藏项";
            var localList =
                (await _localFavoriteStorage.GetFavoriteItemsAsync())
                .Select(p => new TrackableFavorite(p)).ToList();



            Status = "正在读取远程收藏项";
            var remoteList =
                (await _remoteFavoriteStorage.GetFavoriteItemsAsync())
                .Select(p => new TrackableFavorite(p)).ToList();
            var storeList = (await _remoteFavoriteStorage.GetStoresAsync());
            foreach (var store in storeList)
            {
                await _storeStorage.InsertAStore(store);
            }



            Status = "正在合并远程收藏项到本地";
            Dictionary<string, TrackableFavorite> localDictionary =
                new Dictionary<string, TrackableFavorite>();
            await Task.Run(() =>
            {
                localDictionary =
                    localList.ToDictionary(p => p.StoreUid, p => p);

                foreach (var remoteFavorite in remoteList)
                {
                    if (localDictionary.TryGetValue(remoteFavorite.StoreUid,
                        out var localFavorite))
                    {
                        if (remoteFavorite.Timestamp >
                            localFavorite.Timestamp)
                        {
                            localFavorite.IsFavorite =
                                remoteFavorite.IsFavorite;
                            localFavorite.Timestamp = remoteFavorite.Timestamp;
                        }
                    }
                    else
                    {
                        localDictionary[remoteFavorite.StoreUid] =
                            remoteFavorite.CloneAsUpdated();
                    }
                }
            });



            Status = "正在保存本地收藏项";
            foreach (var updatedLocalFavorite in localDictionary.Values.Where(
                p => p.Updated))
            {
                await _localFavoriteStorage.SaveFavoriteAsync(
                    updatedLocalFavorite, false);
            }



            Status = "正在合并本地收藏项到远程";
            Dictionary<string, TrackableFavorite> remoteDictionary =
                new Dictionary<string, TrackableFavorite>();
            await Task.Run(() =>
            {
                remoteDictionary =
                    remoteList.ToDictionary(p => p.StoreUid, p => p);

                foreach (var localFavorite in localList)
                {
                    if (remoteDictionary.TryGetValue(localFavorite.StoreUid,
                        out var remoteFavorite))
                    {
                        if (localFavorite.Timestamp >
                            remoteFavorite.Timestamp)
                        {
                            remoteFavorite.IsFavorite =
                                localFavorite.IsFavorite;
                            remoteFavorite.Timestamp = localFavorite.Timestamp;
                        }
                    }
                    else
                    {
                        remoteDictionary[localFavorite.StoreUid] =
                            localFavorite.CloneAsUpdated();
                    }
                }
            });

            var saveResult1 =
                await _remoteFavoriteStorage.SaveFavoriteItemsAsync(
                    remoteDictionary.Values.Select(p => p as Favorite)
                        .ToList());
            var saveResult2 = await _remoteFavoriteStorage.SaveStoresAsync(remoteDictionary.Values
                .Select(p => p as Favorite)
                .ToList());

            if (saveResult1.Status != ServiceResultStatus.Ok)
            {
                return saveResult1;
            }
            if (saveResult2.Status != ServiceResultStatus.Ok)
            {
                return saveResult2;
            }
            return new ServiceResult { Status = ServiceResultStatus.Ok };
        }

        public async Task<ServiceResult> PunchInfoSyncAsync()
        {
            Status = "正在读取本地打卡记录";
            var localPunchInfoList =
                (await _localPunchInfoStorage.GetAllPunchInfosAsync()).Select(p => new TrackablePunchInfo(p)).ToList();
            Status = "正在读取远程打卡记录";
            var remotePunchInfoList =
                (await _remotePunchInfoStorage.GetPunchInfoItemsAsync()).Select(p => new TrackablePunchInfo(p))
                .ToList();
            foreach (var remotePunchInfo in remotePunchInfoList)
            {
                await _localPunchInfoStorage.SavePunchInfoAsync(remotePunchInfo, false);
            }

            Status = "正在合并远程打卡信息到本地";
            Dictionary<int, TrackablePunchInfo> localPunchInfoDictionary =
                new Dictionary<int, TrackablePunchInfo>();
            await Task.Run(async () =>
            {
                localPunchInfoDictionary =
                    localPunchInfoList.ToDictionary(p => p.Id, p => p);

                foreach (var remotePunchInfo in remotePunchInfoList)
                {
                    if (localPunchInfoDictionary.TryGetValue(remotePunchInfo.Id,
                        out var localPunchInfo))
                    {
                        if (remotePunchInfo.Timestamp >
                            localPunchInfo.Timestamp)
                        {
                            localPunchInfo.Content = remotePunchInfo.Content; 
                            _localImageService.DeleteFolder(localPunchInfo.Timestamp);
                            var image = await _remotePunchInfoStorage.GetImageAsync(remotePunchInfo.Timestamp);
                            for (int i = 0; i < image.Count; i++)
                            {
                                await _localImageService.SaveImageAsync(remotePunchInfo.Timestamp, image[i],
                                    remotePunchInfo.Timestamp + "-" + i + ".png");
                            }

                            localPunchInfo.Timestamp = remotePunchInfo.Timestamp;
                        }
                    }
                    else
                    {
                        localPunchInfoDictionary[remotePunchInfo.Id] =
                            remotePunchInfo.CloneAsUpdated();
                        _localImageService.DeleteFolder(remotePunchInfo.Timestamp);
                        var image= await _remotePunchInfoStorage.GetImageAsync(remotePunchInfo.Timestamp);
                        for (int i = 0; i < image.Count; i++)
                        {
                            await _localImageService.SaveImageAsync(remotePunchInfo.Timestamp, image[i],
                                remotePunchInfo.Timestamp + "-" + i + ".png");
                        }
                    }
                }
            });

            Status = "正在保存本地打卡信息";
            foreach (var updatedLocalPunchInfo in localPunchInfoDictionary.Values.Where(p => p.Updated))
            {
                await _localPunchInfoStorage.SavePunchInfoAsync(updatedLocalPunchInfo, false);
            }

            Status = "正在合并本地打卡信息到远程";
            Dictionary<int, TrackablePunchInfo> remotePunchInfoDictionary =
                new Dictionary<int, TrackablePunchInfo>();
            await Task.Run(async () =>
            {
                remotePunchInfoDictionary =
                    remotePunchInfoList.ToDictionary(p => p.Id, p => p);

                foreach (var localPunchInfo in localPunchInfoList)
                {
                    if (remotePunchInfoDictionary.TryGetValue(localPunchInfo.Id,
                        out var remotePunchInfo))
                    {
                        if (localPunchInfo.Timestamp >
                            remotePunchInfo.Timestamp)
                        {
                            remotePunchInfo.Content =
                                localPunchInfo.Content;
                            var image = await _localImageService.ReadImageAsync(localPunchInfo.Timestamp);
                            await _remotePunchInfoStorage.SaveImageAsync(image, localPunchInfo.Timestamp);
                            await _remotePunchInfoStorage.DeleteAsync(remotePunchInfo.Timestamp);
                            remotePunchInfo.Timestamp = localPunchInfo.Timestamp;
                        }
                    }
                    else
                    {
                        remotePunchInfoDictionary[localPunchInfo.Id] =
                            localPunchInfo.CloneAsUpdated();
                        var image = await _localImageService.ReadImageAsync(localPunchInfo.Timestamp);
                        await _remotePunchInfoStorage.SaveImageAsync(image, localPunchInfo.Timestamp);
                    }
                }
            });
            var saveResult3 = await _remotePunchInfoStorage.SavePunchInfoItemsAsync(remotePunchInfoDictionary.Values
                .Select(p => p as PunchInfo).ToList());
            if (saveResult3.Status != ServiceResultStatus.Ok)
            {
                return saveResult3;
            }
            return new ServiceResult { Status = ServiceResultStatus.Ok };
        }

        /******** 公开方法 ********/

        /// <summary>
        /// 同步服务。
        /// </summary>
        /// <param name="localFavoriteStorage">本地收藏存储。</param>
        /// <param name="remoteFavoriteStorage">远程收藏存储。</param>
        public SyncService(IFavoriteStorage localFavoriteStorage,
            IRemoteFavoriteStorage remoteFavoriteStorage, IStoreStorage storeStorage,
            IPunchInfoStorage punchInfoStorage, IRemotePunchInfoStorage remotePunchInfoStorage,IImageService imageService)
        {
            _localFavoriteStorage = localFavoriteStorage;
            _remoteFavoriteStorage = remoteFavoriteStorage;
            _storeStorage = storeStorage;
            _localPunchInfoStorage = punchInfoStorage;
            _remotePunchInfoStorage = remotePunchInfoStorage;
            _localImageService = imageService;
            remoteFavoriteStorage.StatusChanged += (sender, args) =>
                Status = remoteFavoriteStorage.Status;

        }

        /******** 私有方法 ********/
    }
}
